package com.qcs.ando.manage;

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import android.graphics.Bitmap;

/** ͼƬ������?���ڶ������� */
public class ImageCacheManager extends Manager {

    /** Hard cache, with a fixed maximum capacity */
    public static final int HARD_CACHE_CAPACITY = 3;

    // Hard cache, with a fixed maximum capacity and a life duration
    private/* static final */HashMap<String, Bitmap> sHardBitmapCache = new LinkedHashMap<String, Bitmap>(
            HARD_CACHE_CAPACITY / 2, 0.75f, true) {
        private static final long serialVersionUID = -57738079457331894L;

        @Override
        protected boolean removeEldestEntry(
                LinkedHashMap.Entry<String, Bitmap> eldest) {
            if (size() > HARD_CACHE_CAPACITY) {
                // Entries push-out of hard reference cache are transferred to
                // soft reference cache
                sSoftBitmapCache.put(eldest.getKey(),
                        new SoftReference<Bitmap>(eldest.getValue()));
                return true;
            } else
                return false;
        }
    };

    // Soft cache for bitmap kicked out of hard cache
    private ConcurrentHashMap<String, SoftReference<Bitmap>> sSoftBitmapCache;

    private int mHardCacheCapacity;

    /** ����һ��ͼƬ������������Ĭ��һ����������Ϊ{@link #HARD_CACHE_CAPACITY}�� */
    public ImageCacheManager() {
        sSoftBitmapCache = new ConcurrentHashMap<String, SoftReference<Bitmap>>(
                HARD_CACHE_CAPACITY / 2);
    }

    /**
     * ����һ��ͼƬ������������
     * 
     * @param hardCacheCapacity
     *            һ����������
     */
    public ImageCacheManager(int hardCacheCapacity) {
        this();

        if (0 == hardCacheCapacity) return;

        mHardCacheCapacity = hardCacheCapacity;

        sSoftBitmapCache = new ConcurrentHashMap<String, SoftReference<Bitmap>>(
                mHardCacheCapacity / 2);

        sHardBitmapCache = new LinkedHashMap<String, Bitmap>(
                mHardCacheCapacity / 2, 0.75f, true) {
            private static final long serialVersionUID = -57738079457331894L;

            @Override
            protected boolean removeEldestEntry(
                    LinkedHashMap.Entry<String, Bitmap> eldest) {
                if (size() > (mHardCacheCapacity)) {
                    // Entries push-out of hard reference cache are transferred to
                    // soft reference cache
                    sSoftBitmapCache.put(eldest.getKey(),
                            new SoftReference<Bitmap>(eldest.getValue()));
                    return true;
                } else
                    return false;
            }
        };
    }

    /**
     * @param id
     *            The ID of the image that will be retrieved from the cache.
     * @return The cached bitmap or null if it was not found.
     */
    public Bitmap getBitmap(String id) {
        // First try the hard reference cache
        synchronized (sHardBitmapCache) {
            final Bitmap bitmap = sHardBitmapCache.get(id);
            if (null != bitmap) {
                // Bitmap found in hard cache
                // Move element to first position, so that it is removed last
                sHardBitmapCache.remove(id);
                sHardBitmapCache.put(id, bitmap);
                return bitmap;
            }
        }

        // Then try the soft reference cache
        SoftReference<Bitmap> bitmapReference = sSoftBitmapCache.get(id);
        if (null != bitmapReference) {
            final Bitmap bitmap = bitmapReference.get();
            if (null != bitmap) {
                // Bitmap found in soft cache

                sSoftBitmapCache.remove(id);
                sHardBitmapCache.put(id, bitmap);
                return bitmap;
            } else {
                // Soft reference has been Garbage Collected
                sSoftBitmapCache.remove(id);
            }
        }

        return null;
    }

    public void putBitmap(String id, Bitmap bitmap) {
        synchronized (sHardBitmapCache) {
            if (null != sHardBitmapCache) {
                if (!sHardBitmapCache.containsKey(id)) {
                    sHardBitmapCache.put(id, bitmap);
                }
            }
        }
    }

    public void recycle() {
        try {
            if (null != sHardBitmapCache) {
                Set<Entry<String, Bitmap>> set = sHardBitmapCache.entrySet();

                for (Iterator<Entry<String, Bitmap>> it = set.iterator(); it
                        .hasNext();) {
                    Entry<String, Bitmap> entry = it.next();
                    Bitmap bitmap = entry.getValue();

                    if (null != bitmap && !bitmap.isRecycled()) {
                        bitmap.recycle();
                        bitmap = null;
                    }
                }

                set.removeAll(set);

                sHardBitmapCache.clear();
                sSoftBitmapCache.clear();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
